package com.chs.websocket;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.chs.util.TXTUtil;

import org.springframework.stereotype.Component;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;

import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;

/**
 * WebSocketService
 * @author: mopeiwen
 * @date: 2020年6月16日 下午8:27:49
 */
@ServerEndpoint("/webSocket/{cno}/{pid}/{tno}") // 该注解用来指定一个URI，客户端可以通过这个URI来连接到WebSocket。类似Servlet的注解mapping。无需在web.xml中配置。
@Component
public class WebSocketService {
    // 用来存放每个客户端对应的ChatAnnotation对象，实现服务端与单一客户端通信的话，使用Map来存放，其中Key可以为用户标识，hashtable比hashmap线程安全
    private static Map<String, WebSocketService> webSocketMap = new Hashtable<>();
    // 与某个客户端的连接会话，需要通过它来给客户端发送数据
    private Session session;
    //暂存数据 <receiverId_pid,mess>
    private static Map<String, ArrayList<String>> unInfo = new Hashtable<>();
    
    /**
     * 连接建立成功调用的方法
     * @param session 可选的参数。session为与某个客户端的连接会话，需要通过它来给客户端发送数据
     */
    @OnOpen
    public void onOpen(@PathParam(value = "cno") String cno, @PathParam(value = "pid") String pid, @PathParam(value = "tno") String tno, Session session) {
        this.session = session;
        String uid = cno+"_"+pid+"_"+tno;
        webSocketMap.put(uid,this);//加入map中
        WebSocketService userMap = webSocketMap.get(uid);
        System.out.println(uid+"连接加入！当前在线人数为"+getOnlineCount());
        
        //判断暂存数据是否有自己的信息
        Iterator<Entry<String, ArrayList<String>>> entries = unInfo.entrySet().iterator();
        while(entries.hasNext()){
            Entry<String, ArrayList<String>> entry = entries.next();
            String key = entry.getKey();
            ArrayList<String> value = entry.getValue();
            System.out.println(key+":"+TXTUtil.jointStringList(value, ","));

            if (uid.equals(key)) {
            	try {
            		for (int i = 0; i < value.size(); i++) {
            			userMap.sendMessage(value.get(i));
					}
				} catch (IOException e) {
					e.printStackTrace();
				}
            	break;
			}
        }
    }
    
    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose(@PathParam(value = "cno") String cno, @PathParam(value = "pid") String pid, @PathParam(value = "tno") String tno) {
    	String uid = cno+"_"+pid+"_"+tno;
    	webSocketMap.remove(uid);
        System.out.println(uid+"关闭连接！当前在线人数为" + getOnlineCount());
    }
    
    /**
     * 收到客户端消息后调用的方法
     * @param message 客户端发送过来的消息
     * @param session 可选的参数
     * @json {"userList":["用户"],"mess":"发送信息"}
     */
    @OnMessage
    public void onMessage(@PathParam(value = "cno") String cno, @PathParam(value = "pid") String pid, @PathParam(value = "tno") String tno, String message, Session session) {
    	String uid = cno+"_"+pid+"_"+tno;
    	
    	// 群发消息
        try {
            //将前端发送的 JSON 字符串转换为 JSON 对象
            JSONObject jsonMessge = JSON.parseObject(message);
            //获取接收者ID列表
            //JSONArray list = jsonMessge.getJSONArray("userList");
            //获取发送者的聊天对象
            WebSocketService userMap = webSocketMap.get(uid);
            //获取发送的消息
            String mess=jsonMessge.getString("mess");
                //为自己发送一条消息
                userMap.sendMessage(mess);
                //遍历消息接受者列表
                //for (Object receiverId : list) {
                	String rid = tno+"_"+pid+"_"+cno;
                    //获取消息接受者
                    WebSocketService receiver = webSocketMap.get(rid);
                    
                    if (receiver==null) { //发送对象离线 暂存信息
                    	String key = rid;
                    	String value = mess;
                    	
                    	if (unInfo.containsKey(key)) {
                    		ArrayList<String> vs = unInfo.get(key);
                    		vs.add(value);
                    		unInfo.put(key, vs);
						}else {
							ArrayList<String> vs = new ArrayList<>();
							vs.add(value);
							unInfo.put(key, vs);
						}
					}else {
						//调用session的发送消息方法  将消息发送到客户端
	                    receiver.sendMessage(mess);
					}
                //}
            } catch (Exception e) {
                e.printStackTrace();
            }
    }
    
    /**
     * 发生错误时调用
     * @param session
     * @param error
     */
    @OnError
    public void onError(Throwable error) {
        error.printStackTrace();
    }

    /**
     * 发送消息
     * 这个方法与上面几个方法不一样。没有用注解，是根据自己需要添加的方法。
     * @param message
     * @throws IOException
     */
    public void sendMessage(String message) throws IOException {
        this.session.getBasicRemote().sendText(message);
    }

    /**
     * 发送文件
     * @throws IOException
     */
    public void sendFile(File file)throws IOException{
        this.session.getAsyncRemote().sendObject(file);
    }

    public static synchronized int getOnlineCount() {
        return webSocketMap.size();
    }

}